/*
 * L9Sprite.h
 *
 *  Created on: 2011-10-18
 *      Author: baixp
 */

#ifndef L9SPRITE_H_
#define L9SPRITE_H_
#include <FBase.h>
#include <FGraphics.h>
#include "L9InputStream.h"
#include "L9Animation.h"
#include "L9Util.h"
#include "L9Config.h"
#include <vector>
#include <string>
#include <fstream>
using namespace Osp::Graphics;
using namespace Osp::Base;
using namespace std;
namespace lib9bada {
class L9Sprite {
private:
	byte bZ/*=0*/; //表示是否压缩

	int BS_Flag; //标记
	//////////////////////////////////////////////////
	//    private int _npal = 1; //至少有一种调色板，就是图片本身的调色板
	int _nMaxPal/* = 1*/; //所有图片调色板的最大值
	vector<vector<vector<int> > > _pals;
	vector<int> _trans;
	vector<byte> _image_type; //判断是rgb还是调色板图片
	/**
	 * sprite类型标识,主要由单个module,单个frame、单个动画
	 */
	byte _spriteType;
	// Modules...
	short _nModules; // number of modules
	short _nImages; //图片数
	short _nSounds; //声音数
	vector<short> _images_id;
	vector<short> _modules_w; // width for each module
	vector<short> _modules_h; // height for each module
	vector<byte> _b_misc; //各种标识

	// Frames...
	vector<short> _frames_nfm; // number of FModules (max 256 FModules/Frame)
	vector<short> _frames_fm_start; // index of the first FModule
	vector<short> _frames_w; //帧宽
	vector<short> _frames_h; //帧高
	// FModules...
	static const int K_FM_Bytes_Num = 9;
	short _nFModules;
	byte*/*[]*/_fmodules; // 9 for each FModule(module_id,x,y,flag,pal,isP)

	short _nFrames;
	short _nAFrames;
	short _nAnims;
	short _nMaps; //一直等于1，保留这个的目的是为了与以前的格式兼容，以前允许有多张地图

	// Graphics data (for each module)...
	vector<pByte> _modules_data; // encoded image data for all modules
	vector<vector<Bitmap*> > _modules_image; // cache image for each module / with each palette
	//	int***/*[][][]*/_modules_rgb; // cache rgb for each module / with each palette

	// Anims...
	vector<short> _anims_naf; // number of AFrames
	vector<short> _anims_af_start; // index of the first AFrame
	vector<short> _anims_w;
	vector<short> _anims_h;
	vector<byte> _anims_fps; //fps max 127
	// AFrames...
	static const int K_AF_Bytes_Num = 8;
	byte*/*[]*/_aframes; // 8 int for each AFrame(frame_id,time,x,y)

	vector<int> _share_module_id;
	vector<int> _own_module_id;
	L9Sprite* _spriteShare;

	//断言
	void Assert(int curAnim, int aframe);
	Bitmap* createBitmap(int* pData, int w, int h);
	void defaultInit();
public:
	/**
	 * 默认构造函数
	 */
	L9Sprite();
	/**
	 * 使用file指定的文件来创建CSprite
	 * @param file String
	 */
	L9Sprite(const char* file);

	/**
	 * 根据输入流来创建Sprite对象，L9InputStream为自定义的输入流，为了和C/C++,C#等语言兼容，使用从低到高的字节顺序读取
	 * @param in L9InputStream
	 */
	L9Sprite(L9InputStream& in);
	virtual ~L9Sprite();
	/**
	 * module对应图片的颜色类型，主要有索引色、RGB颜色、带透明色的RGB颜色
	 */
	static const byte K_Color_Type_Index = 0;
	static const byte K_Color_Type_RGB = 1;
	static const byte K_Color_Type_RGBA = 2;

	/**
	 * module数据使用的压缩算法,K_Alpha_Value这个为判断是否带有透明色标识
	 */
	static const byte K_Compress_Type_None = 0;
	static const byte K_Compress_Type_LZ77 = 1;
	static const byte K_Compress_Type_RLE = 2;
	static const byte K_Alpha_Value = 3;

	/**
	 * 表示该sprite是单个的module
	 */
	static const int K_Sprite_Single_Module = 0;
	/**
	 * 表示该sprite是单个的frame
	 */
	static const int K_Sprite_Single_Frame = 1;
	/**
	 * 表示该sprite是单个的animation
	 */
	static const int K_Sprite_Single_Animation = 2;
	/**
	 * 表示该sprite是声音数据
	 */
	static const int K_Sprite_Sound = 3;
	/**
	 * 表示该sprite是一个地图
	 */
	static const int K_Sprite_Map = 4;
	/**
	 * 泛型sprite，表示sprite可能含有module,frame,animation,map,sound中的一种或者几种
	 */
	static const int K_Sprite_General = 5;

	/**
	 * 返回sprite的类型，具体类型请查看sprite类型常量
	 * @return int
	 */
	int getSpriteType();

	/**
	 * 常量Top对齐,setFModule函数(用来替换帧的的Module)的参数，替换的module和原来的module大小不一样是需要选择对齐方式
	 */
	static const int K_Align_Top = 1 << 1;
	/**
	 * 常量Bottom对齐,setFModule函数(用来替换帧的的Module)的参数，替换的module和原来的module大小不一样是需要选择对齐方式
	 */
	static const int K_Align_Bottom = 1 << 2;
	/**
	 * 常量Left对齐,setFModule函数(用来替换帧的的Module)的参数，替换的module和原来的module大小不一样是需要选择对齐方式
	 */
	static const int K_Align_Left = 1 << 3;
	/**
	 * 常量Left对齐,setFModule函数(用来替换帧的的Module)的参数，替换的module和原来的module大小不一样是需要选择对齐方式
	 */
	static const int K_Align_Right = 1 << 4;
	/**
	 * 常量X轴居中对齐,setFModule函数(用来替换帧的的Module)的参数，替换的module和原来的module大小不一样是需要选择对齐方式
	 */
	static const int K_Align_X_Middle = 1 << 5;
	/**
	 * 常量Y轴居中对齐,setFModule函数(用来替换帧的的Module)的参数，替换的module和原来的module大小不一样是需要选择对齐方式
	 */
	static const int K_Align_Y_Middle = 1 << 6;

	/**
	 * 设置图片调色板的颜色，这样可以在程序中通过改变调色板的颜色来达到丰富色彩的目的，比如：在可以DIY主角的游戏往往非常有用
	 * @param img_index int
	 * @param pal_index int
	 * @param color_index int
	 * @param color int
	 */
	void setPalColor(int img_index, int pal_index, int color_index, int color);

	/**
	 * 返回调色板的颜色值
	 * @param img_index int
	 * @param pal_index int
	 * @param color_index int
	 * @return int
	 */
	int getPalColor(int img_index, int pal_index, int color_index);

	/**
	 * sprite对象所包含的动画
	 */
	vector<L9Animation> Animations;

	/**
	 * sprite包含的用来创建声音对象的数据
	 */
	//	byte[][]_sound_data;
	vector<pByte> _sound_data;

	/**
	 * 用来创建地图的数据,比如：地图含有的module,frame,animation,tile等
	 */
	pByte/*[]*/_mapData;

	////////////////////////////////////////////////////////////////////////////////////////////////////
	/**
	 * 加载数据文件
	 * @param sFile String
	 */
	void Load(const char* sFile);

	/**
	 * 加载数据文件
	 * @param file byte[]
	 * @param off int
	 */
	void Load2(L9InputStream& in);

	/**
	 * 缓存pal调色板的m1-m2间的的module数据，如果m2为-1，则缓存m1及m1后的所有module
	 * @param m1 int 开始的module
	 * @param m2 int 结束的module,如果为-1表示 缓存m1及m1后的所有module
	 * @param pal int 针对于某套调色板缓存module数据
	 */
	void cacheImages(int m1, int m2, int pal);

	/**
	 * 判断pal调色板上的module(m1为索引)是否已经缓存了
	 * @param m1 int
	 * @param pal int
	 * @return bool
	 */
	bool isCacheImage(int m1, int pal);
	/**
	 * 释放调色板为pal的m1-m2之间的module
	 * @param m1 int
	 * @param m2 int
	 * @param pal int
	 */
	void freeCacheImages(int m1, int m2, int pal);

	/**
	 * 返回该CSprite的modules数
	 * @return int
	 */
	////////////////////////////////////////////////////////////////////////////////////////////////////
	int getModules();

	/**
	 * 获取module的宽
	 * @param index int
	 * @return int
	 */
	int getModuleWidth(int index);

	/**
	 * 获取module的高
	 * @param index int
	 * @return int
	 */
	int getModuleHeight(int index);

	/**
	 * 获取该module是否含有透明色信息
	 * @param module_id int
	 * @return bool
	 */
	bool getModuleAlpha(int index);

	/**
	 * 返回该sprite的frame数
	 * @return int
	 */
	int getFrames();

	/**
	 * 返回某个Frame的第几个module编号
	 * @param frame int
	 * @param fmodule int
	 * @return int
	 */
	int getFModuleID(int frame, int fmodule);

	/**
	 * 返回某个帧的第fmodule个module在frame中的x坐标
	 * @param frame int
	 * @param fmodule int
	 * @return int
	 */
	int getFModuleX(int frame, int fmodule);

	/**
	 * 返回某个帧的第fmodule个module在frame中的y坐标
	 * @param frame int
	 * @param fmodule int
	 * @return int
	 */
	int getFModuleY(int frame, int fmodule);

	/**
	 * 返回某个帧的第fmodule个module在frame中的调色板
	 * @param frame int
	 * @param fmodule int
	 * @return int
	 */
	int getFModulePal(int frame, int fmodule);

	/**
	 * 获取frame的宽,该帧所有module的并集宽
	 * @param frame int
	 * @return int
	 */
	int getFrameWidth(int frame);

	/**
	 * 获取frame的高,该帧所有module的并集高
	 * @param frame int
	 * @return int
	 */
	int getFrameHeight(int frame);

	/**
	 * 返回该sprite的动画数
	 * @return int
	 */
	int getAnimations();

	/**
	 * 返回动画帧ID，参数是动画帧索引
	 * @param aframe int
	 * @return int
	 */
	int getAFrameID(int curAnim, int aframe);

	/**
	 * 返回动画帧在动画中的X坐标，参数是动画帧索引
	 * @param aframe int
	 * @return int
	 */
	int getAFrameX(int curAnim, int aframe);

	/**
	 * 返回动画帧在动画中的Y坐标，参数是动画帧索引
	 * @param aframe int
	 * @return int
	 */
	int getAFrameY(int curAnim, int aframe);

	/**
	 * 返回动画帧的播放次数，参数是动画帧索引
	 * @param aframe int
	 * @return int
	 */
	int getAFrameTime(int curAnim, int aframe);

	/**
	 * 获取动画的宽,该动画所有frame的并集宽
	 * @return int
	 */
	int getAnimWidth(int curAnim);

	/**
	 * 获取动画的高,该动画所有frame的并集高
	 * @return int
	 */
	int getAnimHeight(int curAnim);

	/**
	 * 返回每秒动画播放的帧数，即fps值
	 * @return int
	 */
	int getAnimFPS(int curAnim);

	/**
	 * 返回动画的帧数
	 * @return int
	 */
	int getAFrames(int curAnim);

	/**
	 * 在位置posX,posY绘制frame
	 * @param g Graphics
	 * @param frame int 要绘制的帧索引
	 * @param posX int 绘制帧的X坐标
	 * @param posY int 绘制帧的Y坐标
	 */
	void paintFrame(Canvas* g, int frame, int posX, int posY);

	/**
	 * 缓存整个帧,实际上就是缓存该帧中的所有module
	 * @param frame int
	 */
	void cacheFrame(int frame);

	/**
	 * 释放该帧的缓存，这样可以减少内存
	 * @param frame int
	 */
	void freeFrameCache(int frame);

	/**
	 * 用模块new_md_id替换掉该帧中所有的模块old_md_id,同时微调坐标，让其对齐
	 * @param frame int
	 * @param old_md_id int
	 * @param new_md_id int
	 */

	void setFModule(int frame, int old_md_id, int new_md_id, int align_flag);

	/**
	 * 用模块new_md_id替换掉所有帧中所有的模块old_md_id,同时微调坐标，让其对齐
	 * @param old_md_id int
	 * @param new_md_id int
	 * @param align_flag int
	 */
	void setFModuleAll(int old_md_id, int new_md_id, int align_flag);

	/**
	 * 设置frame帧的第fmodule个模块在帧中的X坐标
	 * @param frame int
	 * @param fmodule int
	 * @param fm_x int
	 */
	void setFModuleX(int frame, int fmodule, int fm_x);

	/**
	 * 设置frame帧的第fmodule个模块在帧中的Y坐标
	 * @param frame int
	 * @param fmodule int
	 * @param fm_y int
	 */
	void setFModuleY(int frame, int fmodule, int fm_y);

	/**
	 * 设置frame帧的第fmodule个模块在帧中的调色板
	 * @param frame int
	 * @param fmodule int
	 * @param fm_pal int
	 */
	void setFModulePal(int frame, int fmodule, int fm_pal);

	////////////////////////////////////////////////////////////////////////////////////////////////////
	/**
	 * 使用默认调色板绘制module,每一个帧(Frame)画面就是由一个或者多个模块(Module)组成
	 * @param g Graphics
	 * @param module_id int 要绘制的模块ID
	 * @param posX int 要绘制的模块的X坐标
	 * @param posY int 要绘制的模块的Y坐标
	 * @param flags int 绘制时的翻转、旋转信息 主要有X翻转、Y翻转、顺时针旋转90度及它们的组合
	 */
	void paintModule(Canvas* g, int module_id, int posX, int posY, int flags);

	/**
	 * 在游戏中，为了节省资源，两个sprite对象可以共享某些module数据
	 * @param spriteShare L9Sprite
	 * @param share_module_id int[],这个参数记录的是共享的sprite的module
	 * @param own_module_id int[],这个记录的是自己sprite对象没有存储需要使用共享sprite的module，own_module_id应该与share_module_id相对应
	 */
	void setShareModules(L9Sprite* spriteShare, vector<int> share_module_id,
			vector<int> own_module_id);

	/**
	 * 绘制module信息,每一个帧(Frame)画面就是由一个或者多个模块(Module)组成,使用pal指定的调色板来绘制
	 * @param g Graphics
	 * @param module_id int 要绘制的模块ID
	 * @param posX int 要绘制的模块的X坐标
	 * @param posY int 要绘制的模块的Y坐标
	 * @param flags int 绘制时的翻转、旋转信息 主要有X翻转、Y翻转、顺时针旋转90度及它们的组合
	 * @param pal int  使用那套调色板来绘制
	 */
	void paintModule(Canvas* g, int module_id, int posX, int posY, int flags,
			int pal);

	/**
	 * 如果图片已经缓存了，则可以清除创建图片的原始数据，这样可以节省内存,注意调用该函数后，则不能再调用FreeCacheImages等类似释放缓存的函数了，因为没有原始数据了，后面将无法再创建图片
	 */
	void freeImageData();

	/**
	 * 对module数据解码为argb数据 以便于绘制
	 * @param module_id int
	 * @param pal_index int
	 * @return int[]
	 */

	int* decodeImageN(int module_id, int pal_index);

	//////////////////////////////////////////////////////////////////////////////
	/**
	 * module翻转、旋转标识,主要有 X翻转、Y翻转,顺时针旋转90度,实际的使用可能是单独的一个或者他们的组合
	 * 例如：flag=K_Flag_Flip_X|K_Flag_Rotate_90
	 * X翻转标识
	 */
	static const byte K_Flag_Flip_X = 0x01;
	/**
	 * module翻转、旋转标识,主要有 X翻转、Y翻转,顺时针旋转90度,实际的使用可能是单独的一个或者他们的组合
	 * 例如：flag=K_Flag_Flip_X|K_Flag_Rotate_90
	 * Y翻转标识
	 */
	static const byte K_Flag_Flip_Y = 0x02;
	/**
	 * module翻转、旋转标识,主要有 X翻转、Y翻转,顺时针旋转90度,实际的使用可能是单独的一个或者他们的组合
	 * 例如：flag=K_Flag_Flip_X|K_Flag_Rotate_90
	 * 顺时针旋转90度标识
	 */
	static const byte K_Flag_Rotate_90 = 0x04;
	/**
	 * 帧中的module是否为帧的标识,L9Sprite的帧支持包含帧，这个标识用来区分
	 */
	static const byte K_Flag_MD_Frm = 0x08; //这个表示frame_module中存储的是帧，而不是module

	/**
	 * 根据flags标记对图片的rgb数据执行翻转或旋转操作
	 * @param image_data int[]
	 * @param w int
	 * @param h int
	 * @param flags int
	 * @return int[]
	 */
	static int* transformRgb(int* image_data, int w, int h, int flags);

	/**
	 * 对图像旋转270度
	 * @param src int[]
	 * @param width int
	 * @param height int
	 * @return int[]
	 */
	static int* rotate270(int* src, int width, int height);

	/**
	 * 对图像旋转180度
	 * @param src int[]
	 * @param width int
	 * @param height int
	 * @return int[]
	 */
	static int* rotate180(int* src, int width, int height);

	/**
	 * 对图像旋转90度
	 * @param src int[]
	 * @param width int
	 * @param height int
	 * @return int[]
	 */
	static int* rotate90(int* src, int width, int height);

	/**
	 * 对图像进行X轴翻转
	 * @param src int[]
	 * @param width int
	 * @param height int
	 * @return int[]
	 */
	static int* flipY(int* src, int width, int height);

	/**
	 * 对图像进行Y轴翻转
	 * @param src int[]
	 * @param width int
	 * @param height int
	 * @return int[]
	 */
	static int* flipX(int* src, int width, int height);
};
};
#endif /* L9SPRITE_H_ */
